package core.jogo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Tabuleiro {

	int casas[] = new int[32];
	List<Tabuleiro> tabuleirosResultantes;

	public Tabuleiro(){
		int i;
		for(i=0; i<12; i++) casas[i] = 1;
		for(i=12; i<20; i++) casas[i] = 0;
		for(i=20;i<32;i++) casas[i] = -1;
	}

	public Tabuleiro(boolean vazio){
		if(!vazio){
			int i;
			for(i=0; i<12; i++) casas[i] = 1;
			for(i=12; i<20; i++) casas[i] = 0;
			for(i=20;i<32;i++) casas[i] = -1;
		}			
	}

	public Tabuleiro(int[] casas){
		this.casas = casas;
	}




	public List<Tabuleiro> jogadasPossiveis(){	
		if(tabuleirosResultantes != null)
			return tabuleirosResultantes;

		tabuleirosResultantes = new ArrayList<Tabuleiro>();

		List<Jogada> jogadasPossiveis = new ArrayList<Jogada>();
		List<Jogada> jogadasPeca = new ArrayList<Jogada>();
		List<Jogada> jogadasDama = new ArrayList<Jogada>();

		Jogada jogadaCorrente;

		int i, j, contJogadas, maxCapturas = 0, maxCapturasDama=0;
		
		//Percorrendo casas
		for(i = 0 ; i < 32 ; i++){
			if(casas[i] == 2 ){

				//zera as jogadas poss�veis da Dama
				jogadasDama.clear();
				jogadasDama.add(new Jogada(0, i, this));//numeroCapturas, pecaMovida, tabuleiro
				contJogadas = 0;
				while(contJogadas < jogadasDama.size()){
					jogadaCorrente = jogadasDama.get(contJogadas);

					if(capturaEsquerda(jogadaCorrente.pecaMovida, jogadaCorrente.tabuleiro.casas))
						jogadasDama.add(
								new Jogada(jogadaCorrente.numeroCapturas + 1,saltaEsquerda(jogadaCorrente.pecaMovida),
										resulCapEsq(jogadaCorrente.pecaMovida, jogadaCorrente.tabuleiro)));				

					if(capturaDireita(jogadaCorrente.pecaMovida, jogadaCorrente.tabuleiro.casas))
						jogadasDama.add(
								new Jogada(jogadaCorrente.numeroCapturas + 1,saltaDireita(jogadaCorrente.pecaMovida), 
										resulCapDir(jogadaCorrente.pecaMovida, jogadaCorrente.tabuleiro)));	

					if(capturaEsquerdaAbaixo(jogadaCorrente.pecaMovida, jogadaCorrente.tabuleiro.casas))
						jogadasDama.add(
								new Jogada(jogadaCorrente.numeroCapturas + 1,saltaEsquerdaAbaixo(jogadaCorrente.pecaMovida), 
										resulCapEsqAbaixo(jogadaCorrente.pecaMovida, jogadaCorrente.tabuleiro)));	

					if(capturaDireitaAbaixo(jogadaCorrente.pecaMovida, jogadaCorrente.tabuleiro.casas))
						jogadasDama.add(
								new Jogada(jogadaCorrente.numeroCapturas + 1,saltaDireitaAbaixo(jogadaCorrente.pecaMovida), 
										resulCapDirAbaixo(jogadaCorrente.pecaMovida, jogadaCorrente.tabuleiro)));	

					contJogadas++;					

				}
				jogadasDama.remove(0);				
				Collections.sort(jogadasDama);				
				if(!jogadasDama.isEmpty()){
					//Se houver qualquer captura possivel pra Dama, ela j� sobrep�e qualquer jogada de qualquer outra pe�a
					if(jogadasDama.get(jogadasDama.size() - 1).numeroCapturas > maxCapturasDama){
						jogadasPossiveis.clear();
						maxCapturasDama = jogadasDama.get(jogadasDama.size() - 1).numeroCapturas;	
					}					
					if(jogadasDama.get(jogadasDama.size() - 1).numeroCapturas >= maxCapturasDama)
						for(j=jogadasDama.size() - 1; j >= 0 &&
						jogadasDama.get(j).numeroCapturas == 
							jogadasDama.get(jogadasDama.size()-1).numeroCapturas; j--)							
							jogadasPossiveis.add(jogadasDama.get(j));		
				}			
			}//if(casas[i]==2) 
		}
		
		//Percorrendo casas
		for(i = 0 ; i < 32 && maxCapturasDama == 0; i++){
			//h� pe�a minha na casa
			if(casas[i] == 1 ){

				//zera as jogadas poss�veis da pe�a
				jogadasPeca.clear();
				jogadasPeca.add(new Jogada(0, i, this));//numeroCapturas, pecaMovida, tabuleiro
				contJogadas = 0;
				while(contJogadas < jogadasPeca.size()){
					jogadaCorrente = jogadasPeca.get(contJogadas);					
					if(capturaEsquerda(jogadaCorrente.pecaMovida, jogadaCorrente.tabuleiro.casas))
						jogadasPeca.add(
								new Jogada(jogadaCorrente.numeroCapturas + 1,saltaEsquerda(jogadaCorrente.pecaMovida),
										resulCapEsq(jogadaCorrente.pecaMovida, jogadaCorrente.tabuleiro)));

					if(capturaDireita(jogadaCorrente.pecaMovida, jogadaCorrente.tabuleiro.casas))
						jogadasPeca.add(
								new Jogada(jogadaCorrente.numeroCapturas + 1,saltaDireita(jogadaCorrente.pecaMovida), 
										resulCapDir(jogadaCorrente.pecaMovida, jogadaCorrente.tabuleiro)));					

					contJogadas++;					
				}
				jogadasPeca.remove(0);
				Collections.sort(jogadasPeca);
				if(!jogadasPeca.isEmpty()){
					//compara a ultima jogada com o numero max de capturas
					if(jogadasPeca.get(jogadasPeca.size() - 1).numeroCapturas > maxCapturas){
						//se existe uma jogada com numero de capturas maior que o numero maximo,
						//ent�o deletar todas as jogadas possiveis
						//e setar o valor maximo para o tanto de capturas desta jogada!
						jogadasPossiveis.clear();
						maxCapturas = jogadasPeca.get(jogadasPeca.size() - 1).numeroCapturas;	
					}


					//Pega outras jogadas que tem o mesmo numero de capturar que maxCapturas
					if(jogadasPeca.get(jogadasPeca.size() - 1).numeroCapturas >= maxCapturas)

						for(j=jogadasPeca.size() - 1;j >= 0 &&
						jogadasPeca.get(j).numeroCapturas ==jogadasPeca.get(jogadasPeca.size()-1).numeroCapturas;						
						j--)							
							jogadasPossiveis.add(jogadasPeca.get(j));		
				}

			}//if(casas[i]==1)	

		}//for(i = 0 ; i < 32 ; i++)
		
		if(maxCapturas + maxCapturasDama == 0){ //Se não houverem capturas possíveis
			for(i=0;i<32;i++){
				if(casas[i] == 1){
					if(moverEsquerda(i, casas))
						tabuleirosResultantes.add(resulMovEsq(i,this));
					if(moverDireita(i, casas))
						tabuleirosResultantes.add(resulMovDir(i,this));
				}
				if(casas[i] == 2){
					if(moverEsquerda(i, casas))
						tabuleirosResultantes.add(resulMovEsq(i,this));
					if(moverDireita(i, casas))
						tabuleirosResultantes.add(resulMovDir(i,this));
					if(moverEsquerdaAbaixo(i, casas))
						tabuleirosResultantes.add(resulMovEsqAbaixo(i,this));
					if(moverDireitaAbaixo(i, casas))
						tabuleirosResultantes.add(resulMovDirAbaixo(i,this));
				}
			}
		}else
			for(Jogada jog : jogadasPossiveis)
				tabuleirosResultantes.add(jog.tabuleiro);

		return tabuleirosResultantes;

	}

	//dama ok
	private Tabuleiro resulMovDir(int i, Tabuleiro tabuleiro) {
		Tabuleiro novoTabuleiro = new Tabuleiro(true);
		novoTabuleiro.setCasas(tabuleiro.casas.clone());
		//seta a nova posi��o com o valor da pe�a na posicao antiga ([i])
		novoTabuleiro.casas[i+4+i/4%2] = novoTabuleiro.casas[i] ;
		//esvazia a posi��o antiga.
		novoTabuleiro.casas[i] = 0;

		if ((i+4+i/4%2)>27){
			novoTabuleiro.casas[i+4+i/4%2] = 2;
		}

		return novoTabuleiro;
	}
	private Tabuleiro resulMovDirAbaixo(int i, Tabuleiro tabuleiro) {
		Tabuleiro novoTabuleiro = new Tabuleiro(true);
		novoTabuleiro.setCasas(tabuleiro.casas.clone());

		novoTabuleiro.casas[i-4+i/4%2] = novoTabuleiro.casas[i];

		novoTabuleiro.casas[i] = 0;

		//		System.out.println("i: " + i + " MOV: " + (i-4+(i/4%2)) );

		return novoTabuleiro;
	}

	//dama ok
	private Tabuleiro resulMovEsq(int i, Tabuleiro tabuleiro) {
		Tabuleiro novoTabuleiro = new Tabuleiro(true);
		novoTabuleiro.setCasas(tabuleiro.casas.clone());		 
		novoTabuleiro.casas[i+3+i/4%2] = novoTabuleiro.casas[i];
		novoTabuleiro.casas[i] = 0;
		if ((i+3+i/4%2)>27){
			novoTabuleiro.casas[i+3+i/4%2] = 2;
		}
		return novoTabuleiro;
	}

	private Tabuleiro resulMovEsqAbaixo(int i, Tabuleiro tabuleiro) {
		Tabuleiro novoTabuleiro = new Tabuleiro(true);
		novoTabuleiro.setCasas(tabuleiro.casas.clone());
		novoTabuleiro.casas[i-5+i/4%2] = novoTabuleiro.casas[i];
		novoTabuleiro.casas[i] = 0;
		return novoTabuleiro;
	}	

	private boolean moverDireita(int i, int[] casas2) {
		if(i%8 == 7 || i>27)
			return false;
		if(casas[i+4+i/4%2] == 0)
			return true;		
		return false;
	}
	private boolean moverEsquerda(int i, int[] casas) {
		if(i%8 == 0 || i>27)
			return false;
		if(casas[i+3+i/4%2] == 0)
			return true;		
		return false;
	}

	private boolean moverDireitaAbaixo(int i, int[] casas2) {
		if(i % 8 == 7 || i < 4)
			return false;
		if(casas[i-4+i/4%2] == 0)
			return true;		
		return false;
	}
	private boolean moverEsquerdaAbaixo(int i, int[] casas) {
		if(i%8 == 0 || i < 4)
			return false;
		if(casas[i-5+i/4%2] == 0)
			return true;		
		return false;
	}

	//dama ok
	private Tabuleiro resulCapDir(int i, Tabuleiro tabuleiro) {
		Tabuleiro novoTabuleiro = new Tabuleiro(true);
		novoTabuleiro.setCasas(tabuleiro.casas.clone());

		novoTabuleiro.casas[i+4+i/4%2] = 0;
		novoTabuleiro.casas[i+9] = novoTabuleiro.casas[i];
		novoTabuleiro.casas[i] = 0;

		//Verifica se deve virar Dama
		if ((i+9)>27){
			novoTabuleiro.casas[i+9] = 2;
		}

		return novoTabuleiro;
	}
	private Tabuleiro resulCapDirAbaixo(int i, Tabuleiro tabuleiro) {
		Tabuleiro novoTabuleiro = new Tabuleiro(true);
		novoTabuleiro.setCasas(tabuleiro.casas.clone());

		novoTabuleiro.casas[i-4+i/4%2] = 0;
		novoTabuleiro.casas[i-7] = novoTabuleiro.casas[i];
		novoTabuleiro.casas[i] = 0;

		return novoTabuleiro;
	}

	//dama ok
	private Tabuleiro resulCapEsq(int i, Tabuleiro tabuleiro) {
		Tabuleiro novoTabuleiro = new Tabuleiro(true);
		novoTabuleiro.setCasas(tabuleiro.casas.clone());

		novoTabuleiro.casas[i+3+i/4%2] = 0;
		novoTabuleiro.casas[i+7] = novoTabuleiro.casas[i];
		novoTabuleiro.casas[i] = 0;

		if ((i+7)>27){
			novoTabuleiro.casas[i+7] = 2;
		}

		return novoTabuleiro;
	}
	private Tabuleiro resulCapEsqAbaixo(int i, Tabuleiro tabuleiro) {
		Tabuleiro novoTabuleiro = new Tabuleiro(true);
		novoTabuleiro.setCasas(tabuleiro.casas.clone());

		novoTabuleiro.casas[i-5+i/4%2] = 0;
		novoTabuleiro.casas[i-9] = novoTabuleiro.casas[i];
		novoTabuleiro.casas[i] = 0;

		return novoTabuleiro;
	}


	private int saltaDireita(int i) {
		return i+9;
	}
	private int saltaEsquerda(int i) {
		return i+7;
	}

	private int saltaDireitaAbaixo(int i){
		return i-7;
	}
	private int saltaEsquerdaAbaixo(int i){
		return i-9;
	}


	private boolean capturaDireita(int i, int[] casas) {
		if(i%4 == 3 || i > 23)
			return false;
		if(casas[i+4+i/4%2] < 0 && casas[i+9] == 0)
			return true;
		else
			return false;
	}
	private boolean capturaEsquerda(int i, int[] casas) {
		if(i%4 == 0 || i > 23)
			return false;
		if(casas[i+3+i/4%2] < 0 && casas[i+7] == 0)
			return true;
		else
			return false;
	}

	private boolean capturaDireitaAbaixo(int i, int[] casas) {
		if(i%4 == 3 || i < 8)
			return false;
		if(casas[i-4+i/4%2] < 0 && casas[i-7] == 0)
			return true;
		else
			return false;
	}
	private boolean capturaEsquerdaAbaixo(int i, int[] casas) {
		if(i%4 == 0 || i < 9)
			return false;
		if(casas[i-5+i/4%2] < 0 && casas[i-9] == 0)
			return true;
		else
			return false;
	}


	public Tabuleiro inverter(){
		Tabuleiro tab = new Tabuleiro(true);
		int i;
		for(i=0; i<32; i++)
			tab.casas[i] = -this.casas[31-i];
		return tab;
	}

	public int[] getCasas() {
		return casas;
	}

	public void setCasas(int[] casas) {
		this.casas = casas;
	}

}
